#include "Common.h"
#include <fstream>
#include "Exceptions.h"
#include "AudioFile.h"
#include "WaveFile.h"


#define MAKEFOURCC(ch0, ch1, ch2, ch3)  \
	((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) |  \
	((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 ))

#define mmioFOURCC(ch0, ch1, ch2, ch3) \
	MAKEFOURCC(ch0, ch1, ch2, ch3)


#define FOURCC_RIFF     mmioFOURCC('R', 'I', 'F', 'F')
#define FOURCC_DATA     mmioFOURCC('d', 'a', 't', 'a')
#define FOURCC_FMT      mmioFOURCC('f', 'm', 't', ' ')
#define FOURCC_SEEK     mmioFOURCC('S', 'E', 'E', 'K')


namespace Audio
{
	namespace IO
	{
		
		struct WaveFormat
		{
			WORD        wFormatTag;         /* format type */
			WORD        nChannels;          /* number of channels (i.e. mono, stereo...) */
			DWORD       nSamplesPerSec;     /* sample rate */
			DWORD       nAvgBytesPerSec;    /* for buffer estimation */
			WORD        nBlockAlign;        /* block size of data */
			WORD        wBitsPerSample; 
		};

		WaveFile::WaveFile(const String& fileName)
			:AudioFile(fileName)
			,dataPosition(0)
			,dataSize(0)
			,wfm(NULL)
			,wfmSize(0)
		{

		}		
		
		WaveFile::~WaveFile()
		{
			delete wfm;
			Close();
		}

		UINT32 WaveFile::DataPosition()
		{
			return dataPosition;
		}
		UINT32 WaveFile::DataSize()
		{
			return dataSize;
		}		
		void   WaveFile::LoadInfo()
		{
			UINT32 riffHeader[3];
			UINT32 fmtHeader[2];
			UINT32 dataHeader[2];

			dataPosition = 0;

			fileReader->Read((UINT8*)riffHeader, sizeof(riffHeader));
			fileReader->Read((UINT8*)fmtHeader, sizeof(fmtHeader));	

			wfm = new UINT8 [fmtHeader[1]];

			fileReader->Read((UINT8*)wfm, fmtHeader[1]);		
			fileReader->Read((UINT8*)dataHeader, sizeof(dataHeader));


			if(riffHeader[0] != FOURCC_RIFF 
				|| fmtHeader[0] != FOURCC_FMT
				|| dataHeader[0] != FOURCC_DATA
				)
			{
				throw BadFormatException();
			}

			dataSize = dataHeader[1];	
			wfmSize = fmtHeader[1];
			dataPosition = fileReader->Tell();	
		}			

		void*	WaveFile::GetInfo()
		{
			return wfm;
		}
		UINT32	WaveFile::GetInfoSize()
		{
			return wfmSize;
		}

		UINT32 WaveFile::GetChannelCount() const
		{
			//ASSERT(wfmSize >= sizeof(WaveFormat));
			return ((WaveFormat*)wfm)->nChannels;
		}
		UINT32 WaveFile::GetSampleRate() const
		{
			//ASSERT(wfmSize >= sizeof(WaveFormat));
			return ((WaveFormat*)wfm)->nSamplesPerSec;
		}
		UINT32 WaveFile::GetBitsPerSample() const
		{
			//ASSERT(wfmSize >= sizeof(WaveFormat));
			return ((WaveFormat*)wfm)->wBitsPerSample;
		}
		UINT32 WaveFile::GetSampleCount() const
		{
			//ASSERT(wfmSize >= sizeof(WaveFormat));
			WaveFormat* wf = ((WaveFormat*)wfm);
			UINT32 sampleSize = wf->nChannels * wf->wBitsPerSample / 8;
			return dataSize / sampleSize;
		}
	}

}